package xj.graph2d;

import static javax.swing.SwingConstants.CENTER;
import static javax.swing.SwingConstants.HORIZONTAL;
import static javax.swing.SwingConstants.LEFT;
import static javax.swing.SwingConstants.RIGHT;
import static javax.swing.SwingConstants.TOP;
import static javax.swing.SwingConstants.VERTICAL;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.Map;

import xj.graph2d.shapes.HorizontalCompartmentsShape;
import xj.graph2d.util.DrawingUtilities;

public class BoxGroup extends Group {

  public BoxGroup() {
    this(VERTICAL, LEFT);
  }

  public BoxGroup(int orientation) {
    this(orientation, (orientation == VERTICAL) ? LEFT : TOP);
  }

  public BoxGroup(int orientation, int alignment) {
    this.orientation = orientation;
    this.alignment = alignment;
    drawBoxFrame = false;
  }

  @Override
  public DrawShape makeInstance() {
    return new BoxGroup(orientation, alignment);
  }

  @Override
  public void copyTo(DrawShapeBase s) 
    throws CloneNotSupportedException {
    super.copyTo(s);
    if (s instanceof BoxGroup) {
      BoxGroup b = (BoxGroup) s;
      b.setPadding(xpad, ypad);
      b.orientation = orientation;
      b.alignment = alignment;
      b.drawBoxFrame = drawBoxFrame;
    }
  }

  @Override
  public void draw(Graphics2D g2) {
    super.draw(g2);
    if (drawBoxFrame) {
      DrawingUtilities.drawBoxFrame(g2, bounds, true);
    }
  }

  @Override
  public void drawOutline(Graphics2D g2) {
    super.drawOutline(g2);
    if (drawBoxFrame) {
      DrawingUtilities.drawBoxFrame(g2, bounds, false);
    }
  }

  public void setPadding(float xpad, float ypad) {
    this.xpad = xpad;
    this.ypad = ypad;
  }

  protected Color groupFrameColor = new Color(255, 200, 0, 128);

  @Override
  public void drawFrame(Graphics2D g2) {
    int penSize = 1;
    DrawAttr attr = getDrawAttr();
    if (attr != null) {
      penSize = attr.getPenSize();
    }
    float x = (float) bounds.getX();
    float y = (float) bounds.getY();
    float w = (float) bounds.getWidth();
    float h = (float) bounds.getHeight();
    DrawingUtilities.paintBlurFrame(g2, new Rectangle2D.Float(x - 2, y - 2,
							      w + 4, h + 4));
    /*
     * DrawingUtilities.drawRectFrame(g2, bounds, needFrameRect, penSize + 2 *
     * (int) d, groupFrameColor);
     */
  }

  public int getOrientation() {
    return orientation;
  }

  public void setOrientation(int orientation) {
    this.orientation = orientation;
  }

  public int getAlignment() {
    return alignment;
  }

  public void setAlignment(int alignment) {
    this.alignment = alignment;
  }

  @Override
  public String toString() {
    return "Text Box";
  }

  @Override
  public void doLayout() {
    align(true);
    // fitComponents();
    calculateBounds();
  }

  @Override
  public void layoutComponents() {
    align(true);
    calculateBounds();
  }

  public void arrangeShapes() {
    align(true);
    //adjustParentLayout();
  }

  public void align() {
    align(false);
  }

  public void align(boolean arrange) {
    if (orientation == HORIZONTAL) {
      alignVertical(alignment, arrange);
    } else {
      alignHorizontal(alignment, arrange);
    }
  }

  public void alignHorizontal(int mode, boolean arrange) {
    if (debug) {
      System.out.println("BoxGroup.alignHorizontal(): bounds=" + getBoundsString());
    }

    DrawShape shape;
    int n = subshapes.size();
    if (n > 1) {
      boolean first = true;
      int i;
      float maxWidth = 0;
      float leftmost = 0;
      float rightmost = 0;
      for (i = n - 1; i >= 0; i--) {
	shape = subshapes.get(i);
	if (!shape.isVisible()) {
	  continue;
	}

	Rectangle2D r = shape.getBounds();
	float x = (float) r.getX();
	float w = (float) r.getWidth();
	
	if (debug) {
	  System.out.println("BoxGroup.alignHorizontal() @1: i=" + i + 
			     "  x=" + x + "  w=" + w + "  h=" + r.getHeight() + " shape=" + shape);
	}

	if (first) {
	  maxWidth = w;
	  leftmost = x;
	  rightmost = x + w;
	  first = false;
	} else {
	  maxWidth = Math.max(maxWidth, w);
	  leftmost = Math.min(leftmost, x);
	  rightmost = Math.max(rightmost, x + w);
	}
      }

      float center = (leftmost + rightmost) / 2;

      // float top = 0;
      first = true;
      float top = (float) bounds.getY();
      for (i = 0; i < n; i++) {
	shape = subshapes.get(i);
	if (!shape.isVisible()) {
	  continue;
	}

	Rectangle2D r = shape.getBounds();
	float y = (float) r.getY();
	float x = (float) r.getX();
	float w = (float) r.getWidth();
	float h = (float) r.getHeight();

	if (debug) {
	  System.out.println("BoxGroup.alignHorizontal() @2: i=" + i + 
			     "  x=" + x + "  y=" + y + "  w=" + w + "  h=" + h + " top=" + top 
			     + " shape=" + shape);
	}

	float dy = 0;
	if (arrange) {
	  if (first) {
	    first = false;
	    top = y; 
	  } else {
	    top += ypad;
	  }
	  dy = (top - y);
	  top += h;
	}
	switch (mode) {
	case RIGHT:
	  shape.move(rightmost - (x + w), dy);
	  break;
	case CENTER:
	  shape.move(center - (x + w / 2), dy);
	  break;
	case LEFT:
	default:
	  shape.move(leftmost - x, dy);
	  break;
	}
      }
    }
  }

  public void alignVertical(int mode, boolean arrange) {
    if (debug) {
      System.out.println("BoxGroup.alignVertical(): bounds=" + getBoundsString());
    }

    DrawShape shape;
    int n = subshapes.size();
    if (n > 1) {
      int i;
      boolean first = true;
      float maxHeight = 0;
      float top = 0;
      float bottom = 0;
      for (i = n - 1; i >= 0; i--) {
	shape = subshapes.get(i);
	if (!shape.isVisible()) {
	  continue;
	}

	Rectangle2D r = shape.getBounds();
	float y = (float) r.getY();
	float h = (float) r.getHeight();

	if (debug) {
	  System.out.println("BoxGroup.alignVertical() @1: i=" + i +  "  y=" + y + "  h=" + h);
	}

	if (first) {
	  maxHeight = h;
	  top = y;
	  bottom = y + h;
	  first = false;
	} else {
	  maxHeight = Math.max(maxHeight, h);
	  top = Math.min(top, y);
	  bottom = Math.max(bottom, y + h);
	}
      }

      float center = (top + bottom) / 2;

      // float left = 0;
      first = true;
      float left = (float) bounds.getX();
      for (i = 0; i < n; i++) {
	shape = subshapes.get(i);
	if (!shape.isVisible()) {
	  continue;
	}

	Rectangle2D r = shape.getBounds();
	float y = (float) r.getY();
	float x = (float) r.getX();
	float w = (float) r.getWidth();
	float h = (float) r.getHeight();
	float dx = 0;

	if (debug) {
	  System.out.println("BoxGroup.alignVertical() @2: i=" + i + 
			     "  x=" + x + "  y=" + y + "  w=" + w + "  h=" + h);
	}

	if (arrange) {
	  if (first) {
	    first = false;
	    left = x;
	  } else {
	    left += xpad;
	  }
	  dx = (left - x);
	  left += w;
	}
	switch (mode) {
	case RIGHT:
	  shape.move(dx, bottom - (y + h));
	  break;
	case CENTER:
	  shape.move(dx, center - (y + h / 2));
	  break;
	case LEFT:
	default:
	  shape.move(dx, top - y);
	  break;
	}
      }
    }
  }

  public void linkTextLines() {
    //System.out.println("BoxGroup.linkTextLines() " + getClass().getName());

    int n = subshapes.size();
    TextShape curText = null;
    for (int i = 0; i < n; i++) {
      Object o = subshapes.get(i);
      if (o instanceof TextShape) {
	TextShape text = (TextShape) o;
	//System.out.println("BoxGroup.linkTextLines() line[" + i + "]=" + text.getText());
	if (curText != null) {
	  curText.insertAfter(text);
	}
	curText = text;
      }
    }
  }

  @Override
  protected Map<String, Object> getXMLAttributes() {
    Map<String, Object> attrs = super.getXMLAttributes();
    if (attrs == null) {
      attrs = new HashMap<String, Object>();
    }
    attrs.put("orientation", orientation);
    attrs.put("alignment", alignment);
    return attrs;
  }

  @Override
  protected void processXMLAttributes(org.w3c.dom.Element node) {
    if (node != null) {
      super.processXMLAttributes(node);

      String s;
      s = node.getAttribute("orientation");
      try {
	orientation = Integer.parseInt(s);
      } catch (NumberFormatException ex) {
      }
      alignment = LEFT;
      s = node.getAttribute("alignment");
      try {
	alignment = Integer.parseInt(s);
      } catch (NumberFormatException ex) {
      }
    }
  }

  @Override
  protected void arrangeSubshapes() {
    //System.out.println("BoxGroup.arrangeSubshapes()");
    linkTextLines();
    doLayout();
  }

  protected int orientation = VERTICAL;

  protected int alignment = LEFT;

  protected float xpad = 3;

  protected float ypad = 3;

  protected boolean drawBoxFrame = true;

  protected static final boolean debug = false;

}
